from typing import List, Optional
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, delete, and_

from app.db.postgres import get_session
from app.models import Role, RoleMenu, Menu, UserAccount
from app.schemas.role import RoleCreate, RoleRead, RoleMenuSet
from app.schemas.menu import MenuRead
from app.core.security import get_current_user


router = APIRouter(prefix="/roles", tags=["roles"])


@router.get("", response_model=List[RoleRead])
async def list_roles(
    code: Optional[str] = None,
    name: Optional[str] = None,
    enabled: Optional[bool] = None,
    session: AsyncSession = Depends(get_session),
    current_user: UserAccount = Depends(get_current_user),
):
    query = select(Role)
    conds = []
    if code:
        conds.append(Role.code.ilike(f"%{code}%"))
    if name:
        conds.append(Role.name.ilike(f"%{name}%"))
    if enabled is not None:
        conds.append(Role.enabled == enabled)
    if conds:
        query = query.where(and_(*conds))
    result = await session.execute(query)
    roles = result.scalars().all()
    return [RoleRead(id=r.id, code=r.code, name=r.name, description=r.description, enabled=r.enabled) for r in roles]


@router.post("", response_model=RoleRead)
async def create_role(payload: RoleCreate, session: AsyncSession = Depends(get_session), current_user: UserAccount = Depends(get_current_user)):
    exists = await session.execute(select(Role).where(Role.code == payload.code))
    if exists.scalar_one_or_none() is not None:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="角色编码已存在")
    role = Role(code=payload.code, name=payload.name, description=payload.description, enabled=payload.enabled)
    session.add(role)
    await session.flush()
    await session.refresh(role)
    await session.commit()
    return RoleRead(id=role.id, code=role.code, name=role.name, description=role.description, enabled=role.enabled)


@router.get("/{role_id}/menus", response_model=List[MenuRead])
async def get_role_menus(role_id: UUID, session: AsyncSession = Depends(get_session), current_user: UserAccount = Depends(get_current_user)):
    rm = RoleMenu
    result = await session.execute(
        select(Menu).join(rm, rm.menu_id == Menu.id).where(rm.role_id == role_id).order_by(Menu.order_index)
    )
    menus = result.scalars().all()
    return [MenuRead(id=m.id, parent_id=m.parent_id, name=m.name, path=m.path, icon=m.icon, order_index=m.order_index, enabled=m.enabled) for m in menus]


@router.post("/{role_id}/menus")
async def set_role_menus(role_id: UUID, payload: RoleMenuSet, session: AsyncSession = Depends(get_session), current_user: UserAccount = Depends(get_current_user)):
    await session.execute(delete(RoleMenu).where(RoleMenu.role_id == role_id))
    if payload.menu_ids:
        result = await session.execute(select(Menu.id).where(Menu.id.in_(payload.menu_ids)))
        valid_menu_ids = set(result.scalars().all())
        for mid in valid_menu_ids:
            session.add(RoleMenu(role_id=role_id, menu_id=mid))
    await session.flush()
    await session.commit()
    return {"role_id": str(role_id), "menu_ids": [str(m) for m in payload.menu_ids]}
